﻿/**************************************************************
 *
 * 唯一标识：daf62161-4dc2-4b09-9079-567336459a4f
 * 命名空间：Sgr.UPMS.API
 * 创建时间：2023/8/20 17:48:52
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：统一权限管理系统(UPMS)模块启动器
 *      负责UPMS模块的服务注册与初始化
 **************************************************************/

using FluentValidation;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Sgr.Data;
using Sgr.EntityFrameworkCore;
using Sgr.Generator.Segment;
using Sgr.Identity.Services;
using Sgr.Modules;
using Sgr.Organizations;
using Sgr.Security;
using Sgr.Security.Permissions;
using Sgr.Security.Tokens.Services;
using Sgr.UPMS.Application;
using Sgr.UPMS.Application.Commands.Departments;
using Sgr.UPMS.Application.Commands.Duties;
using Sgr.UPMS.Application.Commands.Menus;
using Sgr.UPMS.Application.Commands.Organizations;
using Sgr.UPMS.Application.Commands.Roles;
using Sgr.UPMS.Application.Commands.UserProfile;
using Sgr.UPMS.Application.Commands.Users;
using Sgr.UPMS.Application.Queries;
using Sgr.UPMS.Application.Services;
using Sgr.UPMS.Application.Validations.Departments;
using Sgr.UPMS.Application.Validations.Duties;
using Sgr.UPMS.Application.Validations.Menus;
using Sgr.UPMS.Application.Validations.Organizations;
using Sgr.UPMS.Application.Validations.Roles;
using Sgr.UPMS.Application.Validations.UserProfile;
using Sgr.UPMS.Application.Validations.Users;
using Sgr.UPMS.Domain.Departments;
using Sgr.UPMS.Domain.Duties;
using Sgr.UPMS.Domain.LogLogins;
using Sgr.UPMS.Domain.Menus;
using Sgr.UPMS.Domain.Organizations;
using Sgr.UPMS.Domain.Roles;
using Sgr.UPMS.Domain.Tokens;
using Sgr.UPMS.Domain.Users;
using Sgr.UPMS.Domain.UserTokens;
using Sgr.UPMS.Infrastructure;
using Sgr.UPMS.Infrastructure.Queries;
using Sgr.UPMS.Infrastructure.Repositories;
using Sgr.UPMS.Infrastructure.Sead;

namespace Sgr.UPMS.API
{
    /// <summary>
    /// UPMS模块启动器
    /// 实现了IModuleStartup接口，用于模块的初始化配置
    /// </summary>
    public class ModuleStartup : ModuleStartupBase
    {
        /// <summary>
        /// 配置HTTP请求管道
        /// </summary>
        public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // HTTP管道配置预留
        }

        /// <summary>
        /// 配置模块服务
        /// 注册所有UPMS模块相关的服务
        /// </summary>
        public override void ConfigureServices(IServiceCollection services)
        {
            services.TryAddEnumerable(ServiceDescriptor.Singleton<IPermissionProvider, Permissions>());

            RegisterRepositories<UpmsDbContext>(services);

            #region 组织机构服务注册

            // 仓储与管理服务
            services.AddScoped<IOrganizationManage, OrganizationManage>();

            // 命令验证器
            services.AddTransient<IValidator<CancellationOrgCommand>, CancellationOrgCommandValidator>();
            services.AddTransient<IValidator<CreateOrgCommand>, CreateOrgCommandValidator>();
            services.AddTransient<IValidator<RegisterOrgCommand>, RegisterOrgCommandValidator>();
            services.AddTransient<IValidator<UpdateOrgCommand>, UpdateOrgCommandValidator>();
            services.AddTransient<IValidator<AssociatedParentOrgCommand>, AssociatedParentOrgCommandValidator>();

            services.AddTransient<IValidator<CreateOrgInvitationCommand>, CreateOrgInvitationCommandValidator>();
            services.AddTransient<IValidator<DeleteOrgInvitationCommand>, DeleteOrgInvitationCommandValidator>();

            // 查询服务
            services.AddScoped<IOrganizationQueries, OrganizationQueries>();

            #endregion 组织机构服务注册

            #region 用户服务注册

            // 仓储与管理服务
            services.AddScoped<IUserManage, UserManage>();

            // 命令验证器
            services.AddTransient<IValidator<CreateUserCommand>, CreateUserCommandValidator>();
            services.AddTransient<IValidator<ModifyPasswordCommand>, ModifyPasswordCommandValidator>();
            services.AddTransient<IValidator<ModifyUserCommand>, ModifyUserCommandValidator>();
            services.AddTransient<IValidator<ResetPasswordCommand>, ResetPasswordCommandValidator>();
            services.AddTransient<IValidator<UpdateUserCommand>, UpdateUserCommandValidator>();
            services.AddTransient<IValidator<DeleteUserCommand>, DeleteUserCommandValidator>();
            services.AddTransient<IValidator<ModifyUserStatusCommand>, ModifyUserStatusCommandValidator>();
            services.AddTransient<IValidator<RegisterUserCommand>, RegisterUserCommandValidator>();
            services.AddTransient<IValidator<ForgotPasswordCommand>, ForgotPasswordCommandValidator>();

            services.AddTransient<IValidator<BindEmailCommand>, BindEmailCommandValidator>();
            services.AddTransient<IValidator<BindPhoneCommand>, BindPhoneCommandValidator>();

            // 查询服务
            services.AddScoped<IUserQueries, UserQueries>();
            services.AddScoped<IUserPermissionQueries, UserPermissionQueries>();

            #endregion 用户服务注册

            #region 角色服务注册

            // 仓储与管理服务
            services.AddScoped<IRoleManage, RoleManage>();

            // 命令验证器
            services.AddTransient<IValidator<CreateRoleCommand>, CreateRoleCommandValidator>();
            services.AddTransient<IValidator<UpdateRoleCommand>, UpdateRoleCommandValidator>();
            services.AddTransient<IValidator<AllocateFunctionPermissionCommand>, AllocateFunctionPermissionCommandValidator>();
            services.AddTransient<IValidator<DeleteRoleCommand>, DeleteRoleCommandValidator>();
            services.AddTransient<IValidator<ModifyRoleStatusCommand>, ModifyRoleStatusCommandValidator>();

            // 查询服务
            services.AddScoped<IRoleQueries, RoleQueries>();

            #endregion 角色服务注册

            #region 部门服务注册

            // 仓储与管理服务
            services.AddScoped<IDepartmentManage, DepartmentManage>();

            // 命令验证器
            services.AddTransient<IValidator<CreateDutyCommand>, CreateDutyCommandValidator>();
            services.AddTransient<IValidator<UpdateDutyCommand>, UpdateDutyCommandValidator>();
            services.AddTransient<IValidator<DeleteDutyCommand>, DeleteDutyCommandValidator>();
            services.AddTransient<IValidator<ModifyDutyStatusCommand>, ModifyDutyStatusCommandValidator>();

            // 查询服务
            services.AddScoped<IDepartmentQueries, DepartmentQueries>();

            #endregion 部门服务注册

            #region 职务服务注册

            // 命令验证器
            services.AddTransient<IValidator<CreateDepartmentCommand>, CreateDepartmentCommandValidator>();
            services.AddTransient<IValidator<UpdateDepartmentCommand>, UpdateDepartmentCommandValidator>();
            services.AddTransient<IValidator<DeleteDepartmentCommand>, DeleteDepartmentCommandValidator>();

            // 查询服务
            services.AddScoped<IDutyQueries, DutyQueries>();

            #endregion 职务服务注册

            #region 菜单服务注册

            // 仓储与管理服务
            services.AddScoped<IMenuManage, MenuManage>();

            // 命令验证器
            services.AddTransient<IValidator<CreateMenuCommand>, CreateMenuCommandValidator>();
            services.AddTransient<IValidator<DeleteMenuCommand>, DeleteMenuCommandValidator>();
            services.AddTransient<IValidator<UpdateMenuCommand>, ModifyMenuCommandValidator>();

            // 查询服务
            services.AddScoped<IMenuQueries, MenuQueries>();

            #endregion 菜单服务注册

            #region 认证授权服务注册

            // 临时令牌服务
            services.AddScoped<ITemporaryTokenManager, TemporaryTokenManager>();

            // 认证服务注册（使用Replace确保服务唯一性）
            RegisterAuthenticationServices(services);

            #endregion 认证授权服务注册

            #region 基础设施服务注册

            // 日志和令牌相关仓储
            services.AddScoped<ILogLoginQueries, LogLoginQueries>();

            services.AddScoped<IUpmsSummaryService, UpmsSummaryService>();

            // 序列号生成器
            services.TryAddEnumerable(ServiceDescriptor.Singleton<ISegmentProvider, UpmsSegmentProvider>());

            // MediatR命令处理服务
            services.AddMediatR(cfg =>
            {
                cfg.RegisterServicesFromAssemblyContaining<CreateUserCommand>();
            });

            // 配置选项
            services.AddOptions<UpmsOptions>()
                   .BindConfiguration("Sgr:Upms");

            // 数据库上下文
            AddUpmsDbContext(services);

            // 查询上下文
            services.AddScoped<IUpmsQueryContext, UpmsQueryContext>();

            #endregion 基础设施服务注册

            // 缓存服务
            services.AddScoped<IOrgBasicDataCacheService, OrgDataCacheService>();

            if (services.Any(f => f.ServiceType == typeof(IOrganizationProvider)))
                services.Replace(ServiceDescriptor.Scoped<IOrganizationProvider, OrgDataCacheService>());
            else
                services.AddScoped<IOrganizationProvider, OrgDataCacheService>();

            if (services.Any(f => f.ServiceType == typeof(IUserProvider)))
                services.Replace(ServiceDescriptor.Scoped<IUserProvider, UserDataCacheService>());
            else
                services.AddScoped<IUserProvider, UserDataCacheService>();

            //初始化菜单
            services.TryAddEnumerable(ServiceDescriptor.Transient<IDataBaseInitialize, MenuDataBaseInitialize>());
            services.TryAddEnumerable(ServiceDescriptor.Transient<IDataBaseInitialize, SuperAdminDataBaseInitialize>());
        }

        private static void RegisterRepositories<TDbContext>(IServiceCollection services) where TDbContext : UnitOfWorkDbContext
        {
            services.AddScoped<IOrganizationRepository, OrganizationRepository<TDbContext>>();
            services.AddScoped<IOrganizationInvitationRepository, OrganizationInvitationRepository<TDbContext>>();
            services.AddScoped<IUserRepository, UserRepository<TDbContext>>();
            services.AddScoped<IRoleRepository, RoleRepository<TDbContext>>();
            services.AddScoped<IDepartmentRepository, DepartmentRepository<TDbContext>>();
            services.AddScoped<IDutyRepository, DutyRepository<TDbContext>>();
            services.AddScoped<IMenuRepository, MenuRepository<TDbContext>>();
            services.AddScoped<ITemporaryTokenRepository, TemporaryTokenRepository<TDbContext>>();
            services.AddScoped<ILogLoginRepository, LogLoginRepository<TDbContext>>();
            services.AddScoped<IUserRefreshTokenRepository, UserRefreshTokenRepository<TDbContext>>();
        }

        /// <summary>
        /// 注册认证相关服务
        /// 使用Replace方法确保服务实现的唯一性
        /// </summary>
        private static void RegisterAuthenticationServices(IServiceCollection services)
        {
            // 账户认证服务
            if (services.Any(f => f.ServiceType == typeof(IAccountAuthService)))
                services.Replace(ServiceDescriptor.Scoped<IAccountAuthService, UpmsAccountAuthService>());
            else
                services.AddScoped<IAccountAuthService, UpmsAccountAuthService>();

            // 密码哈希服务
            if (services.Any(f => f.ServiceType == typeof(IPasswordHashService)))
                services.Replace(ServiceDescriptor.Scoped<IPasswordHashService, UpmsPasswordHashService>());
            else
                services.AddScoped<IPasswordHashService, UpmsPasswordHashService>();

            // 功能权限授权服务
            if (services.Any(f => f.ServiceType == typeof(IFunctionPermissionGrantingService)))
                services.Replace(ServiceDescriptor.Singleton<IFunctionPermissionGrantingService, UpmsFunctionPermissionGrantingService>());
            else
                services.AddSingleton<IFunctionPermissionGrantingService, UpmsFunctionPermissionGrantingService>();

            // 临时令牌服务
            if (services.Any(f => f.ServiceType == typeof(ITemporaryTokenService)))
                services.Replace(ServiceDescriptor.Scoped<ITemporaryTokenService, UpmsTemporaryTokenService>());
            else
                services.AddScoped<ITemporaryTokenService, UpmsTemporaryTokenService>();
        }

        /// <summary>
        /// 配置UPMS数据库上下文
        /// 包括读写分离的支持
        /// </summary>
        private static void AddUpmsDbContext(IServiceCollection services)
        {
            //services.AddScoped<ISystemUnitOfWork>(sp => sp.GetRequiredService<UpmsDbContext>());

            // 因为使用了 IRequestRouteContext 来决定是否强制走主库，因此此处暂时不支出使用 AddDbContextPool

            // 配置主数据库上下文
            services.AddDbContext<UpmsDbContext>((sp, builder) =>
            {
                ConfiguratorDbContext(sp, builder, false);
            });

            // 配置只读数据库上下文
            services.AddDbContext<UpmsReadOnlyDbContext>((sp, builder) =>
            {
                ConfiguratorDbContext(sp, builder, true);
            });
        }

        /// <summary>
        /// 配置数据库上下文选项
        /// </summary>
        /// <param name="sp">服务提供者</param>
        /// <param name="builder">数据库上下文选项构建器</param>
        /// <param name="isSlave">是否为从库配置</param>
        private static void ConfiguratorDbContext(IServiceProvider sp, DbContextOptionsBuilder builder, bool isSlave)
        {
            var dataConnectionStringManager = sp.GetRequiredService<IDataConnectionStringManager>();
            var configuratorFactory = sp.GetRequiredService<IDbContextConfiguratorFactory>();
            var option = sp.GetRequiredService<IOptions<UpmsOptions>>();

            // 获取数据库连接字符串配置
            var dataConnectionString = dataConnectionStringManager.GetDataConnectionString(option.Value?.DatabaseName ?? "");
            var configurator = configuratorFactory.CreateConfigurator(dataConnectionString.DbProvider);

            // 根据是否为从库获取连接字符串
            var connectionString = isSlave ?
                GetSlaveConnectionString(sp, dataConnectionString) : dataConnectionString.ConnectionString;

            // 配置数据库连接和日志
            configurator.Configure(builder, connectionString);
            builder.ConfigureLoggingAndErrors(sp);
        }

        /// <summary>
        /// 获取从库连接字符串
        /// </summary>
        private static string GetSlaveConnectionString(IServiceProvider sp, DataConnectionString dataConnectionString)
        {
            // 可选策略：当 IRequestRouteContext 不存在时，默认使用主库（避免 design-time/migration 指向从库）
            IRequestRouteContext? requestRouteContext = sp.GetService<IRequestRouteContext>();
            if (requestRouteContext == null)
            {
                // 记录日志或选择策略：这里选择返回主库连接字符串
                return dataConnectionString.ConnectionString;
            }

            if (requestRouteContext.ForceUseMaster)
                return dataConnectionString.ConnectionString;

            var slaveDataConnectionStringResolve = sp.GetRequiredService<ISlaveDataConnectionStringResolve>();
            return slaveDataConnectionStringResolve.GetSlaveDatabaseConnectionString(dataConnectionString);
        }
    }
}